package org.tgit.gateway.common;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.tgit.gateway.domain.APIServerInfo;
import org.tgit.gateway.domain.ApiGateWayInfo;
import org.tgit.gateway.domain.ApiMonitorInfo;
import org.tgit.gateway.domain.AuthAppApiInfo;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;




public class CommonUtil {
	
	//gson实例化
    private static Gson gson = new GsonBuilder().setDateFormat(
            "yyyy-MM-dd HH:mm:ss").create();
	
	private final static Logger LOGGER = LoggerFactory.getLogger(CommonUtil.class);

	// 用于显示时间戳的格式
	private static final SimpleDateFormat TIMESTAMPFORMAT = new SimpleDateFormat("yyyyMMddHHmmssSSS");

	// 到天的时间戳
	private static final SimpleDateFormat YYYYMMDDFORMAT = new SimpleDateFormat("yyyy-MM-dd");
	// 到秒的时间格式
	private static final SimpleDateFormat YYYYMMDDHHMMSSFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	// 检查提供的host是否连通，如果连通则返回true
	public static boolean isConnected(String host){
	    try{
	        URL url = new URL(host);
	        return isConnected(url.getHost(),url.getPort());
	    }catch(Exception e){
	    	LOGGER.info("isConnected",e);
	        return false;
	    }
	}
	
	public static boolean isConnected(String addr , int port){
	    Socket socket = new Socket();
        try {
            socket.connect(new InetSocketAddress(addr, port));
        } catch (IOException e) {
            LOGGER.error("检查网络失败",e);
            return false;
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                LOGGER.error("关闭网络流失败",e);
            }
        }
        return true;
	}
	
	// 获取本环境的一个标示
	public static String getNodeId(int httpPort){
	    StringBuilder builder = new StringBuilder();
	    builder.append(getLocalHost());
	    builder.append(":").append(httpPort);
	    
	    return builder.toString();
	}
	// 获取本机IP地址
	private static String getLocalHost(){
        try {
            InetAddress ia = InetAddress.getLocalHost();
            return ia.getHostAddress();
        } catch (Exception e) {
            LOGGER.error("获取本机IP地址失败",e);
            return "";
        }
	}
	
	/**
	 * 将传入的字符串转换为SQL语句中的列，如果字符串为空的话，返回null，如果不为空的话，则加上''
	 * @param value
	 * @return
	 */
	public static String getSQLValue(String value){
		if (isEmpty(value)){
			return null;
		}
		return "'" + value + "'";
	}

	/**
	 * 检查当前的消息是否达到可以重发
	 * @param bean
	 * @return
	 */
	/*public static boolean allowDistribute(MsgBean bean){
		if (bean == null){
			return false;
		}
		Date nextExec = bean.getNextExecTime();
		if (nextExec == null || nextExec.before(new Date())){
			return true;
		}
		return false;
	}*/

	/**
	 * 下次可以执行的时间点
	 * @param retryIntervalTime  下次的执行间隔毫秒
	 * @return
	 */
	public static Date getNextExecTime(int retryIntervalTime){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MILLISECOND,retryIntervalTime);

		return calendar.getTime();
	}

	public static Date getDateValue(String date){
		if (isEmpty(date)){
			return null;
		}
		try {
			return YYYYMMDDHHMMSSFORMAT.parse(date);
		} catch (ParseException e) {
			return null;
		}
	}

	// 根据指定的格式返回的时间
	public static Date getDateValue(String date , String format){
		if (isEmpty(date)){
			return null;
		}
		// 如果格式为空，则使用默认格式
		if (isEmpty(format)){
			format = "yyyyMMddHHmmss";
		}
		try{
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
			return  simpleDateFormat.parse(date);
		}catch (Exception e){
		    LOGGER.error("传入的时间格式不正确",e);
			return null;
		}
	}

	public static String getDateStr(Date date){
		if (date == null){
			return "";
		}
		return YYYYMMDDHHMMSSFORMAT.format(date);
	}

	// 将时间以及指定格式转换为字符串
	public static String getTimeStampStr(Date date , SimpleDateFormat format){
		return format.format(date);
	}
	
	// 获取系统当前时间
	public static Date getNow(){
	    return new Date();
	}

	/**
	 * 将字符串转换为int
	 * @param value
	 * @return
	 */
	public static int getIntValue(String value){
		if (isEmpty(value)){
			return 0;
		}
		try{
			return Integer.parseInt(value);
		}catch (Exception e){
		    LOGGER.error("传入的为非数字",e);
			return 0;
		}
	}

	/**
	 * 将字符窜转换为Timestamp格式，传入的字符串格式为 yyyy-MM-dd hh:mm:ss
	 * @param value
	 * @return
	 */
	public static Timestamp getTimestampValue(String value){
		if (isEmpty(value)){
			return null;
		}
		try {
			Date date = YYYYMMDDHHMMSSFORMAT.parse(value);
			return new Timestamp(date.getTime());
		} catch (ParseException e) {
		    LOGGER.error("传入的时间格式不正确",e);
			return null;
		}
	}

	public static long getLongValue(String value){
		if (isEmpty(value)){
			return 0L;
		}
		try{
			return Long.parseLong(value);
		}catch(Exception e){
			LOGGER.error("传入的字符串不是long类型",e);
		}
		return 0L;
	}

	/**
	 * 将字符串转换为xml的字符串
	 * @param value
	 * @return
	 */
	public static String getStringValue(String value){
		if (isEmpty(value)){
			return "";
		}
		return value;
	}

	/**
	 * 将时间字段转换为字符串
	 * @param timestamp
	 * @return
	 */
	public static String getTimestampStr(Timestamp timestamp){
		if (timestamp == null){
			return "";
		}
		return YYYYMMDDHHMMSSFORMAT.format(timestamp);
	}
	/**
	 * 获取今天的时间格式
	 * @return
	 */
	public static String getNowDateFormat(){
		return YYYYMMDDFORMAT.format(new Date());
	}
	/**
	 * 构造一个完整的缓存key
	 * @param key
	 * @param params
	 * @return
	 */
	public static String getCacheKey(String key , String... params){
		if (params == null || params.length == 0){
			return key;
		}
		StringBuilder builder = new StringBuilder();
		builder.append(key);
		for (String param: params) {
			builder.append(ApiConstants.SYMBOL);
			builder.append(param);
		}
		return builder.toString();
	}

	/**
	 * 当收到消息后，给消息增加一个日志ID的编号
	 * 生成规则：时间戳_6位随机值
	 * @return
	 */
	@SuppressWarnings("unused")
	private static String getLogId(){
		StringBuilder builder = new StringBuilder();
		builder.append(TIMESTAMPFORMAT.format(new Date()));
		builder.append(ApiConstants.SYMBOL);
		// 6位随机数
		builder.append(getFixLenthString(6));
		return builder.toString();
	}

	// 返回固定长度的随机值
	private static String getFixLenthString(int length){
		Random rm = new Random(System.currentTimeMillis());
		// 获得随机数
		double pross = (1 + rm.nextDouble()) * Math.pow(10, length);
		// 将获得的获得随机数转化为字符串
		String fixLenthString = String.valueOf(pross);
		// 返回固定的长度的随机数
		return fixLenthString.substring(1, length + 1);
	}
	
	/**
     * 检查Map是否为空
     * @param list
     * @param <T>
     * @return
     */
    @SuppressWarnings("rawtypes")
	public static boolean isEmpty(Map map){
        if (map == null || map.isEmpty()){
            return true;
        }
        return false;
    }
    
    /**
     * 检查Set是否为空
     * @param set
     * @param <T>
     * @return
     */
    public static <T> boolean isEmpty(Set<T> set){
        if (set == null || set.isEmpty()){
            return true;
        }
        return false;
    }

	
	/**
     * 检查集合类是否为空
     * @param list
     * @param <T>
     * @return
     */
    public static boolean isEmpty(Object[] list){
        if (list == null || list.length == 0){
            return true;
        }
        return false;
    }

    /**
     * 检查集合类是否为空
     * @param list
     * @param <T>
     * @return
     */
    public static <T> boolean isEmpty(Vector<T> list){
        if (list == null || list.isEmpty()){
            return true;
        }
        return false;
    }
    
	/**
	 * 检查集合类是否为空
	 * @param list
	 * @param <T>
	 * @return
	 */
	public static <T> boolean isEmpty(List<T> list){
		if (list == null || list.isEmpty()){
			return true;
		}
		return false;
	}

	/**
	 * 判断字符串是否为空
	 * @param str
	 * @return
	 */
	public static boolean isEmpty(String str){
		if(str == null || "".equals(str.trim())){
			return true;
		}
		return false;
	}
	/********************************************json***********************************/
	
    /**
     * //考虑到可能会有的编码问题，所以使用net.sf.json包 ？？
     * 考虑到toJson和fromJson应使用同一个包，否则Date类型处理异常
     * 注：无法处理BLOB等复杂特殊的字段类型
     * @param <T>
     * @param o
     * @return
     */
    public static <T> String toJson(T o) {
        String s = "";
        if (o == null) {
            return s;
        }

        if (o instanceof Collection || o.getClass().isArray()) {
            // 如果是数组
            s = gson.toJson(o);
        } else {
            s = gson.toJson(o);
        }
        return s;
    }
	
    /**
     * 从json转到对象
     * 注：JSONObject.fromObject(o)得到的str，若o某个字段是Date类型，则无法使用gson.fromJson转换
     * @param <T>
     * @param json
     * @param clazz
     * @return
     */
    public static <T> T fromJson(String json, Class<T> clazz) {
        return gson.fromJson(json, clazz);
    }
    public static <T> List<T> fromJsonArray(String json, Class<T> clazz) {
    	//Json的解析类对象
        JsonParser parser = new JsonParser();
        //将JSON的String 转成一个JsonArray对象
        JsonArray jsonArray = parser.parse(json).getAsJsonArray();

        Gson gson = new Gson();
        List<T> result = new ArrayList<T>();

        //加强for循环遍历JsonArray
        for (JsonElement item : jsonArray) {
            //使用GSON，直接转成Bean对象
            T bean = gson.fromJson(item, clazz);
            result.add(bean);
        }
        return result;
    }
    
    /*********************************************log日志处理****************************************/
    /**
     * 
    * @Title: getMsg   
    * @Description: 将传入的内容拼接为日志格式
    * @author fanzaijun  
    * @date 2018年10月25日 下午3:15:09   
    * @param dir
    * @param className
    * @param method
    * @param args
    * @param space
    * @return  
    * String  
    * @throws (没有异常抛出)
     */
    public static String getMsg(String dir,String className,String methodName,Object args,long space){
        StringBuilder builder = new StringBuilder();
        builder.append(dir).append(ApiConstants.DELIMITER);
        builder.append(className).append(ApiConstants.DELIMITER);
        builder.append(methodName).append(ApiConstants.DELIMITER);
        builder.append(toJson(args)).append(ApiConstants.DELIMITER);
        builder.append("exec-time=").append(space);
        return  builder.toString();
    }
	/**
	 * 
	* @Title: getMsg   
	* @Description: 将传入的内容拼接为日志格式
	* @author fanzaijun  
	* @date 2018年10月25日 下午3:19:57   
	* @param dir
	* @param className
	* @param method
	* @param args
	* @return  
	* String  
	* @throws (没有异常抛出)
	 */
	public static String getMsg(String dir,String className,String methodName,Object... args){
	    StringBuilder builder = new StringBuilder();
        builder.append(dir).append(ApiConstants.DELIMITER);
        builder.append(className).append(ApiConstants.DELIMITER);
        builder.append(methodName).append(ApiConstants.DELIMITER);
        if (args != null){
            for (Object obj : args) {
                builder.append(toJson(obj)).append(",");
            }
        }
        return  builder.toString();
	}
	/**
	 * 
	* @Title: getAccessUriAppCodeAccessToken  
	* @Description: 数据拼接
	* @author fanzaijun  
	* @date 2018年10月25日 下午6:12:11   
	* @param authAppApiInfo
	* @return  
	* String  格式是：accessUri_appcode_token_api
	* @throws (没有异常抛出)
	 */
	public static  String getAccessUriAppCodeAccessToken(AuthAppApiInfo authAppApiInfo) {
		StringBuilder builder = new StringBuilder();
		builder.append(authAppApiInfo.getAccessUri());
		builder.append(ApiConstants.SYMBOL);
		builder.append(authAppApiInfo.getAppCode());
		builder.append(ApiConstants.SYMBOL);
		builder.append(authAppApiInfo.getAccessToken());
		return ApiConstants.GATEWAY_PRE_KEY + MD5Utils.md5(builder.toString());
	}
	/**
	 * 
	 * @Title: getAccessUriAppCodeAccessToken  
	 * @Description: 数据拼接
	 * @author fanzaijun  
	 * @date 2018年10月25日 下午6:12:11   
	 * @param authAppApiInfo
	 * @return  
	 * String  格式是：accessUri_appcode_token_api
	 * @throws (没有异常抛出)
	 */
	public static  String getAccessUriAppCodeAccessToken(String reqUri,String appCode,String accessToken) {
		StringBuilder builder = new StringBuilder();
		builder.append(reqUri);
		builder.append(ApiConstants.SYMBOL);
		builder.append(appCode);
		builder.append(ApiConstants.SYMBOL);
		builder.append(accessToken);
		return ApiConstants.GATEWAY_PRE_KEY + MD5Utils.md5(builder.toString());
	}
	
	/**
	 * 对象转换器-转换成网关对象
	* @Title: convertApiGateWayBean   
	* @Description: 对象转换器
	* @author fanzaijun  
	* @date 2018年10月26日 下午2:30:51   
	* @param apiServerBean
	* @return  
	* ApiGateWayBean  
	* @throws (没有异常抛出)
	 */
	public static ApiGateWayInfo convertApiGateWayBean(APIServerInfo apiServerInfo) {
		ApiGateWayInfo gateWayInfo = new ApiGateWayInfo();
		gateWayInfo.setApiId(apiServerInfo.getApiId());
		gateWayInfo.setMaxConcurrency(apiServerInfo.getMaxConcurrency());
		gateWayInfo.setAccessUri(apiServerInfo.getAccessUri());
		gateWayInfo.setDeployUri(apiServerInfo.getUri());
		gateWayInfo.setMethod(apiServerInfo.getMethod());
		// 当前数据库中还未审核或拒绝的话，则不需要同步到网关
		// 0:正常，1：关闭，2：过期，3：未启用，4：所有服务器都失效,-1:不需要加载
		int apiStatus = getApiStatus(apiServerInfo);
		if (apiStatus == -1) {
			return null;
		}
		gateWayInfo.setStatus(apiStatus);
		return gateWayInfo;
	}
	/**
	 * 获取API的状态
	* @Title: getApiStatus   
	* @Description: 0:正常，1：关闭，2：过期，3：未启用，4：所有服务器都失效,-1:不需要加载
	* @author fanzaijun  
	* @date 2018年10月26日 下午3:03:04   
	* @param apiServerInfo
	* @return  
	* int  
	* @throws (没有异常抛出)
	 */
	public static int getApiStatus(APIServerInfo apiServerInfo) {
		int status = ApiConstants.GATEWAY_API.STATUS_NORMAL;
		//判断当前API的状态
		switch (apiServerInfo.getStatus()) {
			//0:API处于待审核
			case ApiConstants.API_DOMAIN_STATUS_PENDING:
				//赋值-1
				status = ApiConstants.NO_NEED_LOAD;
				break;
			//2：API处于审核退回
			case ApiConstants.API_DOMAIN_STATUS_REJECT:
				//赋值-1
				status = ApiConstants.NO_NEED_LOAD;
				break;
			//4:API处于关闭状态
			case ApiConstants.API_DOMAIN_STATUS_CLOSE:
				//赋值1
				status = ApiConstants.GATEWAY_API.STATUS_CLOSE;
				break;
			//3:API处于审核通过
			case ApiConstants.API_DOMAIN_STATUS_OK:
				//赋值0
				status = ApiConstants.GATEWAY_API.STATUS_NORMAL;
				break;
			//其他情况都是-1，需要重新加载到网关
			default:
				//赋值-1
				status = ApiConstants.NO_NEED_LOAD;
				break;
		}
		// 只要不是正常状态的API，都直接返回状态码
		if (status != ApiConstants.GATEWAY_API.STATUS_NORMAL) {
			return status;
		}
		//正常情况继续执行
		Date now = getNow();
		// 还未启动，
		// 判断开始时间和结束时间：begin<end
		if (apiServerInfo.getBeginAccTime() != null && apiServerInfo.getBeginAccTime().after(now)) {
			//返回状态3
			return ApiConstants.GATEWAY_API.STATUS_NOT_USED;
		}
		// 时间过期 expire
		if (apiServerInfo.getEndAccTime() != null && apiServerInfo.getEndAccTime().before(now)) {
			//赋值2
			return ApiConstants.GATEWAY_API.STATUS_EXPIRE;
		}
		// 正常赋值0
		return ApiConstants.GATEWAY_API.STATUS_NORMAL;
	}
	

	/**
	 *  
	* @Title: getDeployURL   
	* @Description: 获取部署的URL,解析格式
	* @author fanzaijun  
	* @date 2018年10月26日 下午3:02:54   
	* @param apiServerBean
	* @return  
	* String  
	* @throws (没有异常抛出)
	 */
	public static String getDeployURL(APIServerInfo apiServerInfo) {
		
		String host = apiServerInfo.getHost();
		String uri = apiServerInfo.getUri();
		
		StringBuilder url = new StringBuilder();
		if (host.endsWith("/")) {
			url.append(host.substring(0, host.length() - 1));
		} else {
			url.append(host);
		}
		url.append("/");
		if (uri.startsWith("/")) {
			url.append(uri.substring(1));
		} else {
			url.append(uri);
		}

		return url.toString();
	}
	
	// 网关日志：将网关中的JSON串转换为Bean对象
	public static ApiMonitorInfo parseToApiMonitorDetailBean(Cache gatewayCache,String json,String serviceId) {
		ApiMonitorInfo apiMonitorInfo = fromJson(json, ApiMonitorInfo.class);
		if(null==apiMonitorInfo.getApiId()){
			return null;
		}
		// 获取真实Token
		String realToken = MessageQueueUtil.getRealAccessToken(gatewayCache, apiMonitorInfo, serviceId);
		apiMonitorInfo.setAccessToken(realToken);
		return apiMonitorInfo;
	}

	//LOGID生成规则
    public static String genLogid() {
    	return UUID.randomUUID().toString().replaceAll("-", "");
    }
}
